/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.BeginRequestMessage;
import cn.easyplatform.messages.request.SwitchOrgRequestMessage;
import cn.easyplatform.messages.response.SwitchOrgResponseMessage;
import cn.easyplatform.messages.vos.*;
import cn.easyplatform.spi.service.ApplicationService;
import cn.easyplatform.spi.service.TaskService;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.FieldVo;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.web.WebApps;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.layout.ILayoutManagerFactory;
import cn.easyplatform.web.layout.IMainTaskBuilder;
import cn.easyplatform.web.layout.LayoutManagerFactory;
import cn.easyplatform.web.listener.LogoutListener;
import cn.easyplatform.web.log.LogManager;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.listener.SessionValidationScheduler;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.MainTaskSupport;
import cn.easyplatform.web.utils.TaskInfo;
import cn.easyplatform.web.utils.WebUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.Sessions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class MainLayoutController extends AbstractLayoutController {

    @Override
    protected void init(Component comp) {
        if (WebApps.me().isSessionKeepAlive()) {
            if (comp instanceof Borderlayout) {
                Div div = new Div();
                div.setZclass("h-100 w-100");
                Page page = comp.getPage();
                comp.detach();
                div.appendChild(comp);
                div.setPage(page);
                SessionValidationScheduler.start(div);
            } else
                SessionValidationScheduler.start(comp);
        }
        WebApps.me().subscribe(comp.getDesktop());
    }


    /**
     * 设定系统的标题
     *
     * @param c
     */
    public void title(Component c) {
        EnvVo env = Contexts.getEnv();
        if (c instanceof Label) {
            Label header = (Label) c;
            header.setValue(env.getName());
        } else if (c instanceof A) {
            A a = (A) c;
            a.setLabel(env.getName());
        }
    }

    /**
     * 选择机构
     *
     * @param c
     */
    public void selectOrg(Component c) {
        final OrgVo org = (OrgVo) c.getAttribute("value");
        final AuthorizationVo av = (AuthorizationVo) c.getDesktop().getSession()
                .getAttribute(Contexts.PLATFORM_USER_AUTHORIZATION);
        if (av.getOrgId().equals(org.getId()))
            return;
        Messagebox.show(Labels.getLabel("user.switch.org",
                new String[]{org.getName()}), Labels
                        .getLabel("message.dialg.title.warning"), Messagebox.YES
                        | Messagebox.NO, Messagebox.EXCLAMATION,
                new EventListener<Event>() {
                    @Override
                    public void onEvent(Event evt) throws Exception {
                        if (evt.getName().equals(Messagebox.ON_YES)) {
                            List<String> agents = null;
                            if (av.getAgents() != null
                                    && !av.getAgents().isEmpty()) {
                                agents = new ArrayList<String>();
                                for (AgentVo agent : av.getAgents())
                                    agents.add(agent.getId());
                            }
                            ApplicationService ac = ServiceLocator
                                    .lookup(ApplicationService.class);
                            IResponseMessage<?> resp = ac
                                    .switchOrg(new SwitchOrgRequestMessage(org
                                            .getId(), agents));
                            if (resp.isSuccess()) {
                                SwitchOrgResponseMessage msg = (SwitchOrgResponseMessage) resp;
                                if (msg.getRoles() != null)
                                    av.setRoles(msg.getRoles());
                                if (msg.getAgents() != null) {
                                    for (int i = 0; i < msg.getAgents().size(); i++) {
                                        av.getAgents()
                                                .get(i)
                                                .setRoles(
                                                        msg.getAgents().get(i)
                                                                .getRoles());
                                    }
                                }
                                Contexts.getEnv().setMainPage(msg.getBody());
                                av.setOrgId(org.getId());
                                av.setOrgName(org.getName());
                                Executions.sendRedirect("");
                                Clients.confirmClose("");
                            } else
                                MessageBox.showMessage(resp);
                        }
                    }
                });
    }

    /**
     * 当前机构
     *
     * @return
     */
    public String getOrgId() {
        AuthorizationVo av = (AuthorizationVo) Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_AUTHORIZATION);
        return av.getOrgId();
    }

    /**
     * 机构名称
     *
     * @return
     */
    public String getOrgName() {
        AuthorizationVo av = (AuthorizationVo) Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_AUTHORIZATION);
        return av.getOrgName();
    }

    /**
     * 当前用户所属的机构
     *
     * @return
     */
    public Object getOrgs() {
        Object orgs = Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_ORGS);
        if (orgs == null)
            return new ArrayList<OrgVo>(0);
        return orgs;
    }

    /**
     * 显示多个机构
     *
     * @param parent
     */
    public void orgs(Component parent) {
        Object val = Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_ORGS);
        if (val == null) {
            if (!(parent instanceof Menupopup))
                parent.setVisible(false);
        } else {
            EventListener evt = new EventListener() {
                @Override
                public void onEvent(Event event) throws Exception {
                    if (event.getTarget() instanceof Combobox) {
                        Combobox cbx = (Combobox) event.getTarget();
                        cbx.setAttribute("value", cbx.getSelectedItem().getAttribute("value"));
                    }
                    selectOrg(event.getTarget());
                }
            };
            AuthorizationVo av = (AuthorizationVo) Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_AUTHORIZATION);
            List<OrgVo> orgs = (List<OrgVo>) val;
            if (parent instanceof Combobox) {
                for (OrgVo ov : orgs) {
                    Comboitem item = new Comboitem();
                    item.setLabel(ov.getName());
                    item.setParent(parent);
                    item.setAttribute("value", ov);
                    if (av.getOrgId().equals(ov.getId())) {
                        Combobox cbx = (Combobox) parent;
                        cbx.setSelectedItem(item);
                    }
                }
                parent.addEventListener(Events.ON_CHANGE, evt);
            } else if (parent instanceof Menupopup) {
                for (OrgVo ov : orgs) {
                    Menuitem item = new Menuitem();
                    item.setLabel(ov.getName());
                    item.setParent(parent);
                    item.setAttribute("value", ov);
                    item.addEventListener(Events.ON_CLICK, evt);
                    if (av.getOrgId().equals(ov.getId())) {
                        item.setChecked(true);
                        item.setCheckmark(true);
                    }
                }
            }
        }
    }

    /**
     * 判断给定的角色是否在当前用户中
     *
     * @param roles
     * @return
     */
    public boolean isRole(String roles) {
        AuthorizationVo av = (AuthorizationVo) Sessions.getCurrent().getAttribute(Contexts.PLATFORM_USER_AUTHORIZATION);
        String[] array = roles.split(",");
        for (RoleVo rv : av.getRoles()) {
            for (int i = 0; i < array.length; i++) {
                if (rv.getId().equals(array[i]))
                    return true;
            }
        }
        if (av.getAgents() != null && !av.getAgents().isEmpty()) {
            for (AgentVo agent : av.getAgents()) {
                for (RoleVo rv : agent.getRoles()) {
                    for (int i = 0; i < array.length; i++) {
                        if (rv.getId().equals(array[i]))
                            return true;
                    }
                }
            }
        }
        return false;
    }


    /**
     * 是否是移动端页面
     *
     * @return
     */
    public boolean isMobile() {
        return "mil".equals(Contexts.getEnv().getDeviceType());
    }


    /**
     * 设定系统的菜单
     *
     * @param navbar
     */
    public void menu(Component navbar) {
        ILayoutManagerFactory lmf = LayoutManagerFactory.createLayoutManager();
        lmf.getMenuBuilder(navbar).fill(Contexts.getUserAuthorzation());
//        final IntroJs wizard = (IntroJs) Executions.getCurrent().getSession().removeAttribute("wizard");
//        if (wizard != null) {
//            Integer step = (Integer) wizard.getAttribute("step");
//            final Component parent = navbar.getRoot();
//            final Options options = wizard.getOptionsObj();
//            if (step != null) {
//                Step[] steps = new Step[options.getSteps().size() - step];
//                Step[] old = new Step[options.getSteps().size()];
//                options.getSteps().toArray(old);
//                System.arraycopy(old, step, steps, 0, steps.length);
//                options.getSteps().clear();
//                List<Component> comps = new ArrayList<>();
//                if (navbar instanceof Navbar) {
//                    Iterator<Component> itr = navbar.queryAll("nav,navitem").iterator();
//                    while (itr.hasNext())
//                        comps.add(itr.next());
//                } else if (navbar instanceof Tree) {
//                    Iterator<Component> itr = navbar.queryAll("treeitem").iterator();
//                    while (itr.hasNext())
//                        comps.add(itr.next());
//                }
//                int size = comps.size();
//                for (Step s : steps) {
//                    Component c = parent.getFellowIfAny(s.getElement());
//                    if (c == null) {
//                        for (int i = 0; i < size; i++) {
//                            Component comp = comps.get(i);
//                            String id = (String) comp.getAttribute("id");
//                            if (s.getElement().equals(id)) {
//                                s.setElement(comp.getUuid());
//                                if (s.getActionList() != null) {
//                                    for (Action action : s.getActionList()) {
//                                        for (int j = 0; j < size; j++) {
//                                            comp = comps.get(j);
//                                            id = (String) comp.getAttribute("id");
//                                            if (action.getActionCompId().equals(id)) {
//                                                action.setActionCompId(comp.getUuid());
//                                                break;
//                                            }
//                                        }
//                                    }
//                                }
//                                options.getSteps().add(s);
//                                break;
//                            }
//                        }
//                    } else {
//                        if (s.getActionList() != null) {
//                            for (Action action : s.getActionList()) {
//                                for (int j = 0; j < size; j++) {
//                                    Component comp = comps.get(j);
//                                    String id = (String) comp.getAttribute("id");
//                                    if (action.getActionCompId().equals(id)) {
//                                        action.setActionCompId(comp.getUuid());
//                                        break;
//                                    }
//                                }
//                            }
//                        }
//                        options.getSteps().add(s);
//                    }
//                }
//            }
//            final IntroJs introJs = new IntroJs();
//            introJs.setOptionsObj(options);
//            introJs.addEventListener(IntroJs.ON_NEXT, new WizardEventListener());
//            parent.appendChild(introJs);
//            parent.addEventListener("onLater", new EventListener<Event>() {
//                @Override
//                public void onEvent(Event event) throws Exception {
//                    introJs.start();
//                }
//            });
//            Events.echoEvent("onLater", parent, null);
//        }
    }


    /**
     * 关闭功能
     *
     * @param ref
     */
    public void close(Component ref, int type) {
        Component c = ref.getDesktop().getFirstPage().getFellowIfAny("gv5container");
        if (c != null && c instanceof Tabbox) {
            Tabbox tbbox = (Tabbox) c;
            List<Tab> tabs = tbbox.getTabs().getChildren();
            List<Tab> closableTabs = new ArrayList<Tab>();
            for (Tab tab : tabs) {
                if (tab.getValue() != null) {
                    if (type == 0) {// 关闭当前功能
                        if (tab.isSelected()) {
                            closableTabs.add(tab);
                            break;
                        }
                    } else if (type == 1) {// 关闭其它功能
                        if (!tab.isSelected())
                            closableTabs.add(tab);
                    } else {// 关闭所有功能
                        closableTabs.add(tab);
                    }
                }
            }
            for (Tab tab : closableTabs) {
                MainTaskSupport task = tab.getValue();
                task.close(false);
            }
        }
    }

    /**
     * 通过循环迭代子组件panel来执行主页功能
     *
     * @param comp
     * @deprecated
     */
    public void home(Component comp) {
        ILayoutManagerFactory lmf = LayoutManagerFactory.createLayoutManager();
        lmf.getHomeBuilder().fill(comp, Contexts.getUserAuthorzation());
    }


    /**
     * 执行指定的功能
     *
     * @param c
     * @param taskId
     */
    public void go(Component c, String taskId) {
        go(c, taskId, Constants.OPEN_MODAL, null);
    }

    /**
     * 执行指定的功能
     *
     * @param c
     * @param taskId
     */
    public void go(Component c, String taskId, String params) {
        go(c, taskId, Constants.OPEN_MODAL, params);
    }

    /**
     * @param c
     * @param taskId
     * @param openMode
     */
    public void go(Component c, String taskId, int openMode) {
        go(c, taskId, openMode, null);
    }

    /**
     * @param c
     * @param taskId
     * @param openMode
     * @param params
     */
    public void go(Component c, String taskId, int openMode, String params) {
        Component container = c.getPage().getFellowIfAny("gv5container");
        if (container == null) {
            container = c;
            openMode = Constants.OPEN_MODAL;
        } else if (openMode == Constants.OPEN_POPUP)
            container = c;
        TaskInfo taskInfo = new TaskInfo(taskId);
        if (openMode == Constants.OPEN_NORMAL) {
            int code = WebUtils.checkTask(taskInfo, container);
            if (code == 1 || code == 0) {
                if (code == 1)
                    MessageBox.showMessage(Labels
                            .getLabel("message.dialog.title.error"), Labels
                            .getLabel("main.task.has.run",
                                    new String[]{taskId}));
                return;
            }
        }
        TaskVo tv = new TaskVo(taskId);
        if (!Strings.isBlank(params)) {
            List<FieldVo> variables = new ArrayList<>();
            for (String param : params.split("&")) {
                String[] keyValue = param.split("=");
                variables.add(new FieldVo(keyValue[0], FieldType.VARCHAR, keyValue[1]));
            }
            tv.setVariables(variables);
        }
        tv.setOpenModel(openMode);
        TaskService mtc = ServiceLocator
                .lookup(TaskService.class);
        BeginRequestMessage req = new BeginRequestMessage(tv);
        IResponseMessage<?> resp = mtc.begin(req);
        if (resp.isSuccess()) {
            if (resp.getBody() != null
                    && resp.getBody() instanceof AbstractPageVo) {
                AbstractPageVo pv = (AbstractPageVo) resp.getBody();
                if (openMode == Constants.OPEN_NORMAL) {
                    taskInfo.setId(pv.getId());
                    taskInfo.setTitle(pv.getTitile());
                    taskInfo.setImage(pv.getImage());
                    WebUtils.registryTask(taskInfo);
                }
                MainTaskSupport builder = null;
                try {
                    LogManager.beginRequest();
                    builder = (MainTaskSupport) LayoutManagerFactory
                            .createLayoutManager()
                            .getMainTaskBuilder(container,
                                    tv.getId(), pv);
                    ((IMainTaskBuilder) builder).build();
                } catch (EasyPlatformWithLabelKeyException ex) {
                    builder.close(false);
                    MessageBox.showMessage(ex);
                } catch (BackendException ex) {
                    builder.close(false);
                    MessageBox.showMessage(ex.getMsg().getCode(), (String) ex
                            .getMsg().getBody());
                } catch (Exception ex) {
                    if (log.isErrorEnabled())
                        log.error("doTask", ex);
                    builder.close(false);
                    MessageBox.showMessage(
                            Labels.getLabel("message.dialog.title.error"),
                            ex.getMessage());
                } finally {
                    LogManager.endRequest();
                }
            }
        } else
            MessageBox.showMessage(resp);
    }

    /**
     * 登出
     */
    public void logout(String url) {
        EnvVo env = Contexts.getEnv();
        env.setLogoutUrl(url);
        LogoutListener.logout(env);
    }
}
